/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo All rights
 * reserved.
 */
package ac.jp.u_tokyo.SyncLib.tests;

import static org.junit.Assert.*;

import java.util.Stack;

import org.antlr.runtime.RecognitionException;
import org.junit.Before;
import org.junit.Test;

import ac.jp.u_tokyo.SyncLib.IDSync;
import ac.jp.u_tokyo.SyncLib.Mod;
import ac.jp.u_tokyo.SyncLib.Sync;
import ac.jp.u_tokyo.SyncLib.SyncFactory;
import ac.jp.u_tokyo.SyncLib.SynchronizationFailedException;
import ac.jp.u_tokyo.SyncLib.graphCombinator.GraphCombinatorFactory;
import ac.jp.u_tokyo.SyncLib.modParser.ModParser;

public class GraphCombinatorStateTest
{
	private class IDStub extends IDSync
	{
		int _index;
		public IDStub(boolean Param1OverParam2, int index)
		{
			super(Param1OverParam2);
			_index = index;
		}

		@Override
		public void cancelRevertPoint()
		{
			states.pop();
//			System.out.println(_index + ": state committed: " + states);
		}

		@Override
		public void revert()
		{
			State = states.pop();
//			System.out.println(_index + ": state reverted : " + states);
		}

		@Override
		public void setRevertPoint()
		{
			states.push(State);
//			System.out.println(_index + ": state recorded : " + states);
		}

		@Override
		public Mod[] resynchronize(Object[] values, Mod[] modifications)
				throws SynchronizationFailedException
		{
			Mod[] result = super.resynchronize(values, modifications);
			State++;
			return result;
		}

		@Override
		public Mod[] synchronize(Mod[] modifications)
				throws SynchronizationFailedException
		{
//			System.out.println(_index + ": Sync called..");
			Mod[] result = super.synchronize(modifications);
			State++;
			return result;
		}

		public int State = 0;

		public Stack<Integer> states = new Stack<Integer>();
	}

	IDStub _id1, _id2, _id3, _id4;

	Sync _sync;

	Sync createSync()
	{
		final GraphCombinatorFactory f = new GraphCombinatorFactory();
		f.setParaVars("a", "b");
		f.setOtherVars("x");
		f.setInitialValues(null, null);
		f.connectSync(new SyncFactory() {

			public Sync create()
			{
				return _id2;
			}

		}, "x", "b");
		f.connectSync(new SyncFactory() {

			public Sync create()
			{
				return _id1;
			}

		}, "a", "x");

		GraphCombinatorFactory result = new GraphCombinatorFactory();
		result.setParaVars("a", "b", "c");
		result.setOtherVars("x");
		result.setInitialValues(null, null, null);
		result.connectSync(new SyncFactory() {

			public Sync create()
			{
				return f.create();
			}

		}, "a", "x");
		result.connectSync(new SyncFactory() {

			public Sync create()
			{
				return _id3;
			}

		}, "x", "b");
		result.connectSync(new SyncFactory() {

			public Sync create()
			{
				return _id4;
			}

		}, "x", "c");

		

		return result.create();
	}

	@Before
	public void setUp()
	{
		_id1 = new IDStub(true, 1);
		_id2 = new IDStub(true, 2);
		_id3 = new IDStub(true, 3);
		_id4 = new IDStub(true, 4);
		_sync = createSync();
	}

	@Test
	public void testInvokeOnce() throws SynchronizationFailedException,
			RecognitionException
	{
		_sync.synchronize(ModParser.parse("200, nomod, nomod"));
		assertEquals(1, _id1.State);
		assertEquals(1, _id2.State);
		assertEquals(1, _id3.State);
		assertEquals(1, _id4.State);
	}

	@Test
	public void testFail1() throws SynchronizationFailedException,
			RecognitionException
	{
		_sync.synchronize(ModParser.parse("{a->1}, nomod, nomod"));
		try
		{
			_sync.synchronize(ModParser.parse("{a->2}, {a->3}, nomod"));
		}
		catch (SynchronizationFailedException e)
		{
			assertEquals(1, _id1.State);
			assertEquals(1, _id2.State);
			assertEquals(1, _id3.State);
			return;
		}
		fail();
	}

	@Test
	public void testFail2() throws SynchronizationFailedException,
			RecognitionException
	{
		_sync.synchronize(ModParser.parse("{a->1}, nomod, nomod"));
		try
		{
			_sync.synchronize(ModParser.parse("{a->2}, {b->3}, {a->3}"));
		}
		catch (SynchronizationFailedException e)
		{
			assertEquals(1, _id1.State);
			assertEquals(1, _id2.State);
			assertEquals(1, _id3.State);
			return;
		}
		fail();
	}

}
